
package com.starshineworks.entities;

import com.starshineworks.util.*;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.*;

 
public class EntityE extends Object {
            
    public Integer _id;
    public String  _name;
    public String  _display;

    protected EntityE() {
    }
    
    protected EntityE(Integer id) {
        this._id = id;
    }
    
    public String displayName() {
        return packageName();
    }
    
    public static String packageName() {
        return (new EntityE()).getClass().getPackage().getName();
    }

    public static Integer create(String typeName, Map<String,String[]> map) {
        try {
            Class cls = Class.forName("com.starshineworks.entities." + typeName);
            return create(cls, map);
        }
        catch (Exception e) {
            Util.handleException(e);
            return null;
        }
    }

    public static Integer create(Class cls, Map<String,String[]> map) {
        try {
            ObjectContainer client = DbUtil.openClient();
            Constructor ctor = cls.getConstructor(Integer.class);
            Integer id = Util.nextId();
            Object o = ctor.newInstance(id);
            client.store(o);
            client.close();
            EntityE.updateObjectFields(o, map);
            return id;
        }
        catch (Exception e){
            Util.handleException(e);
            return null;
        }
    }
    
    public Map<String,Object> getFieldNamesAndValues() {
        Map<String,Object> fieldsAndValues = new HashMap<String,Object>();
        Class cls = this.getClass();
        Field[] locFields = cls.getDeclaredFields();
        Field[] supFields = EntityE.class.getDeclaredFields();
        Field[] fields = Util.<Field>concatArrays(supFields, locFields);
        for (Integer i = 0; i < fields.length; i++) {
            Field f = fields[i];
            int mod = f.getModifiers();
            if (!Modifier.isPublic(mod) || Modifier.isStatic(mod)) {
                continue;
            }
            String key = f.getName();            
            Object val = null;
            try {
                val = f.get(this);
            }
            catch (Exception e) {
                Util.handleException(e);
            }
            if (val != null) {
                fieldsAndValues.put(key, val);
            }
        }
        return fieldsAndValues;
    }
                    
    public static List<EntityE> retrieve(Object proto) {
        List<EntityE> list = new ArrayList<EntityE>();
        try {
            ObjectContainer client = DbUtil.openClient();
            ObjectSet result = client.queryByExample(proto);
            client.close();
            if (result == null) {
                return list;
            }
            if (result.isEmpty()) {
                return list;
            }
            for (Integer i = 0; i < result.size(); i++) {
                list.add((EntityE)result.get(i));
            }
            
        } catch (Exception e) {
            Util.handleException(e);
        }
        return list;
    }

    /* XXXX
    public static EntityE retrieveById(Integer id) {
        EntityE o = null;
        List<EntityE> list = retrieve(new EntityE(id));
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }*/

    // The assumption is that the entity object's member fields are 
    // of type Integer, String, Integer[], String[]. Nothing else is 
    // handled by this function.
    public static void updateObjectFields(Object               proto, 
                                          Map<String,String[]> map) {
        try {
            ObjectContainer client = DbUtil.openClient();
            // Must re-load the object in this transaction.
            Object o = client.queryByExample(proto).get(0);
            // do not close! we are updating.
            Field[] locFields = o.getClass().getDeclaredFields();
            Field[] supFields = EntityE.class.getDeclaredFields();
            Field[] fields = Util.<Field>concatArrays(supFields, locFields);
            for (Integer i = 0; i < fields.length; i++) {
                Field f = fields[i];
                String key = f.getName();
                Class cls = f.getType();
                String xx = cls.getName();
                boolean isSingle = !cls.isArray();
                cls = isSingle ? cls : cls.getComponentType();
                boolean isInt = cls == Integer.class;
                try {
                    String[] strs = map.get(key);
                    if (strs == null) {
                        continue;
                    }
                    Integer len = strs.length;
                    Object[] vals = new Object[len];
                    for (Integer v = 0; v < strs.length; v++) {
                        String str = strs[v];
                        Object val = str;
                        if (str != null) {
                            if (isInt) {
                                val = new Integer(str);
                            }
                        }
                        vals[v] = val;
                    }
                    if (isSingle) {
                        f.set(o, vals[0]);
                        continue;
                    }
                    if (isInt) {
                        Integer[] ivals = new Integer[len];
                        for (Integer v = 0; v < vals.length; v++) {
                            ivals[v] = (Integer)vals[v];
                        }
                        f.set(o, ivals);                        
                    } else {
                        String[] svals = new String[len];
                        for (Integer v = 0; v < vals.length; v++) {
                            svals[v] = (String)vals[v];
                        }
                        f.set(o, svals);
                    }                    
                    
                } catch (Exception e) {
                    Util.handleException(e);
                }
            }
            
            client.store(o);
            client.close();

        } catch (Exception e) {
            Util.handleException(e);
        }
    }
    
    public String refreshDisplay(int view)
    {
        _display = "XXXX Name is " + _name;
        if (view != Util.HTMLViewNone) {
            List<String> keys = new ArrayList<String>();
            keys.add("Name");
            keys.add("ID");
            List<String> vals = new ArrayList<String>();
            vals.add(_name);
            vals.add(_id.toString());
            if (view == Util.HTMLViewTable) {
                List<List<String>> t = new ArrayList<List<String>>();
                t.add(vals);
                _display = Util.asHTMLTable(keys, t);
                return _display;
            }
            return "***ERROR 564***";
        }
        return _display;
    }
            
    public static boolean initAll() {
        if (false) 
        return false;
        /// XXXX
        DbUtil.reset();
        UserE.init();
        TeamE.init();
        FieldE.init();
        return true;
    }

}